/*
 *  main.c
 *  
 *
 *  Created by Philip Asare on 12/6/10.
 *  Copyright 2010. All rights reserved.
 *
 *
 * monome sketch-it base station 
 *
 * communication
 * -------------
 * to controllers --> wireless (RT-Link)
 * to console display --> UART
 *
 */


#include <nrk.h>
#include <include.h>
#include <ulib.h>
#include <stdio.h>
#include <avr/sleep.h>
#include <hal.h>
#include <rt_link.h>
#include <nrk_error.h>
#include <nrk_timer.h>
#include <nrk_ext_int.h>
#include <nrk_events.h>
#include <nrk_defs.h>

/* interrupts */

#define INC NRK_DEBUG_2
#define SEND NRK_DEBUG_3


#define INC_INT NRK_EXT_INT_0
#define SEND_INT NRK_EXT_INT_1

/* controller tx slots --> base station rx slots */
#define MY_TX 2
#define MY_RX 4

/* controller state info */

uint8_t state, prev_state;

#define NUM_STATES 8

/* for controller:
 * if(SYNC)
 *		state <-- player_number
 *		assign player number (if valid)
 *			state = select
 * else
 *		state <-- state
 *		change to new state
 */

#define SYNC 0
#define SELECT 1
#define PREGAME 2
#define GAMEPLAY 3
#define PLAYERASSIGN 4
#define GAMEOVER_CALC 5
#define GAMEOVER_CHOICE 6

#define PLAYER1 1
#define PLAYER2 2
#define PLAYER3 3
#define PLAYER4 4

uint8_t tx_len = PKT_DATA_START;

/* task setup */

NRK_STK Stack1[NRK_APP_STACKSIZE];
nrk_task_type TaskOne;
void Task1(void);

NRK_STK StackTX[NRK_APP_STACKSIZE];
nrk_task_type TaskTX;
void tx_task(void);

inline void display_state(uint8_t state);

void state_inc();
void send();

inline void monome_comm_init();

void nrk_create_taskset();

uint8_t tx_buf[RF_MAX_PAYLOAD_SIZE];
uint8_t rx_buf[RF_MAX_PAYLOAD_SIZE];

nrk_sig_t tx_sig;

int
main ()
{
	//uint16_t div;
	nrk_setup_ports();
	nrk_setup_uart(UART_BAUDRATE_115K2);
	
	printf( "Starting up...\r\n" );
	
	/* button input pins */
	nrk_gpio_direction(NRK_DEBUG_2, NRK_PIN_INPUT);
	nrk_gpio_direction(NRK_DEBUG_3, NRK_PIN_INPUT);
	
	/* configure interrupts */
	nrk_ext_int_configure(INC_INT, NRK_RISING_EDGE, state_inc);
	//nrk_ext_int_configure(SEND_INT, NRK_RISING_EDGE, send );
	
	tx_sig =nrk_signal_create();
	
	nrk_init();
	
	nrk_led_clr(0);
	nrk_led_clr(1);
	nrk_led_clr(2);
	nrk_led_clr(3);
	
	nrk_time_set(0,0);
	
	
	rtl_task_config();
	
	nrk_create_taskset ();
	
	nrk_start();
	
	return 0;
}

void Task1()
{
	monome_comm_init();
	
	
	printf("started\r\n");
	while(!rtl_ready())  nrk_wait_until_next_period(); 
	nrk_ext_int_enable(INC_INT);
	//nrk_ext_int_enable(SEND_INT);
	while(1){
		display_state(state);
		nrk_wait_until_next_period();
	}
}

void tx_task(){
	int8_t cnt = 0;
	printf("started\r\n");
	while(!rtl_ready())  nrk_wait_until_next_period(); 
	while(1){
		if(cnt == 50){
			cnt = 0;
			if(state != prev_state){
				nrk_led_toggle(GREEN_LED);
				while( rtl_tx_pkt_check(MY_TX)!=0 );
				
				tx_buf[PKT_DATA_START] = state;
				rtl_tx_pkt( tx_buf, tx_len, MY_TX);
				nrk_led_toggle(BLUE_LED);
				rtl_wait_until_tx_done(MY_TX);
				nrk_led_toggle(BLUE_LED);
				nrk_led_toggle(GREEN_LED);
				prev_state = state;
			}
		}
		
		//toggle before and after checks for the tasks existence
		nrk_led_toggle(RED_LED);
		nrk_wait_until_next_period();
		cnt++;
		nrk_led_toggle(RED_LED);
	}
	// to check if the task exits the while loop, which shouldn't happen
	nrk_led_set(RED_LED);
}



void
nrk_create_taskset()
{
	
	
	TaskOne.task = Task1;
	TaskOne.Ptos = (void *) &Stack1[NRK_APP_STACKSIZE-1];
	TaskOne.Pbos = (void *) &Stack1[0];
	TaskOne.prio = 3;
	TaskOne.FirstActivation = TRUE;
	TaskOne.Type = BASIC_TASK;
	TaskOne.SchType = PREEMPTIVE;
	TaskOne.period.secs = 0;
	TaskOne.period.nano_secs = 120*NANOS_PER_MS;
	TaskOne.cpu_reserve.secs = 0;
	TaskOne.cpu_reserve.nano_secs = 50*NANOS_PER_MS;
	TaskOne.offset.secs = 0;
	TaskOne.offset.nano_secs= 0;
	nrk_activate_task (&TaskOne);
	
	TaskTX.task = tx_task;
	TaskTX.Ptos = (void *) &StackTX[NRK_APP_STACKSIZE-1];
	TaskTX.Pbos = (void *) &StackTX[0];
	TaskTX.prio = 2	;
	TaskTX.FirstActivation = TRUE;
	TaskTX.Type = BASIC_TASK;
	TaskTX.SchType = PREEMPTIVE;
	TaskTX.period.secs = 0;
	TaskTX.period.nano_secs = 120*NANOS_PER_MS;
	TaskTX.cpu_reserve.secs = 0;
	TaskTX.cpu_reserve.nano_secs = 50*NANOS_PER_MS;
	TaskTX.offset.secs = 0;
	TaskTX.offset.nano_secs= 0;
	nrk_activate_task (&TaskTX);
	
	
	printf ("Create done\r\n");
}

inline void monome_comm_init(){
	rtl_init (RTL_COORDINATOR);
	
	/* rx schedules */
	rtl_set_schedule( RTL_RX,MY_RX, 1 );
	
	
	/* tx schedules */
	rtl_set_schedule( RTL_TX, MY_TX, 1 );
	
	
	rtl_start();
	rtl_rx_pkt_set_buffer(rx_buf, RF_MAX_PAYLOAD_SIZE);
	prev_state = -1;
}

void state_inc(){
	while(nrk_gpio_get(INC));
	state = (state+1)%NUM_STATES;
	//printf("state inc!\r\n");
}

void send(){
	while(nrk_gpio_get(SEND));
	nrk_led_toggle(BLUE_LED);
	nrk_event_signal(tx_sig);
	nrk_led_toggle(BLUE_LED);
}

inline void display_state(uint8_t state){
	if(state & 0x01){
		nrk_led_set(RED_LED);
	}
	else{
		nrk_led_clr(RED_LED);
	}
	if(state & 0x02){
		nrk_led_set(GREEN_LED);
	}
	else{
		nrk_led_clr(GREEN_LED);
	}
	if(state & 0x04){
		nrk_led_set(BLUE_LED);
	}
	else{
		nrk_led_clr(BLUE_LED);
	}
	if(state & 0x08){
		nrk_led_set(ORANGE_LED);
	}
	else{
		nrk_led_clr(ORANGE_LED);
	}
	//x	printf("current state: %d\r\n", state);
}



